Skip to content

[Main] feat: api 요청시 게이트웨이세서 파싱된 토큰 사용하도록#54

Merged
ksoheee merged 1 commit intomainfrom
feat/#30
Nov 9, 2025
Merged

[Main] feat: api 요청시 게이트웨이세서 파싱된 토큰 사용하도록#54
ksoheee merged 1 commit intomainfrom
feat/#30

Conversation

@ksoheee
Copy link
Contributor

@ksoheee ksoheee commented Nov 9, 2025

📝 Summary

  • 토큰 사용하도록 변경

Summary by CodeRabbit

릴리스 노트

  • Bug Fixes

    • 사용자 인증 정보를 기반으로 한 접근 제어 강화로 권한 관련 이슈 개선
  • Refactor

    • 구매 주문 관련 API 엔드포인트의 사용자 컨텍스트 통합으로 요청자 정보 자동 파악
    • 사용자 권한에 따른 데이터 조회 범위 자동 설정으로 보안 강화

@ksoheee ksoheee self-assigned this Nov 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

Walkthrough

구매 주문 API의 모든 엔드포인트에 사용자 컨텍스트(UserContext) 파라미터를 추가하고, 관련 서비스 메서드 시그니처를 업데이트했습니다. 요청 DTO에서 요청자 필드를 제거하고, 서비스 구현에서 사용자 컨텍스트로부터 요청자 정보를 도출하는 방식으로 변경했습니다.

Changes

Cohort / File(s) 변경 요약
컨트롤러 계층
src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java
모든 주요 엔드포인트(requestPurchaseOrder, getPendingOrders, getProcessedOrders, getCanceledOrders, getHeadPurchaseOrderDetail, getPurchaseOrderDetail, getBranchPurchaseOrders, getBranchPurchaseOrdersByFilter, getCompleteRepairParts, approve, processShipment, reject)에 @CurrentUser UserContext user 파라미터 추가. 서비스 호출 시 UserContext를 첫 번째 인자로 전달하도록 수정. branchCode/engineerId 기반 파라미터에서 user 기반 접근으로 변경.
요청 DTO
src/main/java/com/gearfirst/backend/api/order/dto/request/PurchaseOrderRequest.java
요청자 관련 4개 필드 제거: requesterId (Long), requesterName (String), requesterRole (String), requesterCode (String).
서비스 인터페이스
src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderService.java
모든 메서드에 UserContext user 파라미터 추가: createPurchaseOrder, getPendingOrders, getProcessedOrders, getCancelOrders, getHeadPurchaseOrderDetail, getBranchPurchaseOrders, getBranchPurchaseOrdersByFilter, getCompleteRepairPartsList, getPurchaseOrderDetail, approveOrder, ship, rejectOrder. branchCode/engineerId 파라미터 제거 및 메서드 시그니처 단순화.
서비스 구현
src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java
UserContext 기반 사용자 검증 로직 추가. 요청자 정보(requesterId, requesterName, requesterRole, requesterCode)를 UserContext로부터 도출. 모든 주요 메서드에서 role 기반 접근 제어 강화. 프라이빗 헬퍼 메서드 validUser(UserContext) 추가. 본사(總社) 전용 엔드포인트 접근 검증 추가.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant Repo as Repository

    Client->>Controller: GET /orders/pending<br/>(`@CurrentUser` UserContext)
    activate Controller
    
    Controller->>Service: getPendingOrders(user,<br/>startDate, endDate,<br/>searchKeyword, pageable)
    activate Service
    
    Note over Service: validUser(user)<br/>Derive requesterCode<br/>from region + workType
    
    Service->>Service: Access control check<br/>(if 본사 required)
    
    Service->>Repo: Query orders by<br/>requesterCode, userId,<br/>date range, etc.
    activate Repo
    Repo-->>Service: PageResponse
    deactivate Repo
    
    Service-->>Controller: PageResponse<br/>HeadPurchaseOrderResponse
    deactivate Service
    
    Controller-->>Client: JSON response
    deactivate Controller
Loading

Estimated code review effort

🎯 4 (복잡함) | ⏱️ ~45분

상세 검토 필요 영역:

  • PurchaseOrderServiceImpl의 사용자 검증 로직: 각 메서드에서 validUser() 호출 및 role 기반 접근 제어가 일관되게 적용되었는지 확인 필요. 특히 본사(總社) 전용 메서드들의 권한 검증이 정확한지 검토
  • requesterCode 도출 방식: UserContext의 region과 workType으로부터 requesterCode를 계산하는 로직이 모든 메서드에서 동일하게 적용되었는지 확인. 기존의 명시적 파라미터 방식과의 호환성 검토
  • 데이터 접근 제어: getBranchPurchaseOrders, getBranchPurchaseOrdersByFilter 등에서 branchCode와 engineerId 파라미터 제거 후 UserContext만으로 올바른 데이터 필터링이 이루어지는지 확인
  • DTO 필드 제거의 영향: PurchaseOrderRequest에서 요청자 필드 4개를 제거함에 따라 클라이언트와의 API 계약(contract) 변경. 기존 요청 형식과의 호환성 이슈 확인
  • 메서드 시그니처 일관성: 모든 서비스 메서드의 파라미터 순서(user 항상 첫 번째)와 호출 부분 일치 여부 확인

Possibly related PRs

Suggested reviewers

  • qwice

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명이 매우 간단하며, 템플릿의 대부분의 필수 섹션(관련 이슈, 질문/요점, 참고 자료)이 누락되어 있습니다. 관련 이슈 번호, PR 과정에서 주의할 사항, 참고 자료 등을 추가하여 더 완전한 설명을 제공해주세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 게이트웨이에서 파싱된 토큰을 사용하도록 변경하는 내용을 명확히 설명하며, 변경 사항의 주요 목적을 잘 반영하고 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#30

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32b3a80 and 1751706.

📒 Files selected for processing (4)
  • src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java (5 hunks)
  • src/main/java/com/gearfirst/backend/api/order/dto/request/PurchaseOrderRequest.java (0 hunks)
  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderService.java (1 hunks)
  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java (14 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/com/gearfirst/backend/api/order/dto/request/PurchaseOrderRequest.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-28T05:05:49.715Z
Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 26
File: src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java:93-98
Timestamp: 2025-10-28T05:05:49.715Z
Learning: In the Gear-First order backend (gearfirst-order-BE) Java Spring Boot project, when an endpoint performs state changes on the PurchaseOrder entity (such as calling order.completeRepair()), ensure the endpoint's Operation summary and description clearly document that state modification occurs, and use appropriate HTTP methods (POST/PATCH/PUT) rather than GET, even if the endpoint also returns data.

Applied to files:

  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java
  • src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java
  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderService.java
📚 Learning: 2025-10-30T09:27:59.696Z
Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 28
File: src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java:146-148
Timestamp: 2025-10-30T09:27:59.696Z
Learning: In the gearfirst-order-BE project, the `completeRepairAndGetParts` method in `PurchaseOrderServiceImpl` is called exclusively from the repair reception page, ensuring that the `receiptNum` parameter is always present and does not require null validation.

Applied to files:

  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java
  • src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java
  • src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderService.java

Comment on lines +49 to +55
Long userId = Long.parseLong(user.getUserId());
String userName = user.getUsername();
String role = user.getRank();
String workType = user.getWorkType();
String region = user.getRegion();
String requesterCode = region + workType;

Copy link

@coderabbitai coderabbitai bot Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

숫자가 아닌 userId에 대한 예외 처리 누락

게이트웨이가 내려주는 UserContext.userId는 외부 입력과 동일한 신뢰 수준인데, 지금은 Long.parseLong(user.getUserId())를 바로 호출하고 있어서 숫자가 아니면 NumberFormatException이 터져 5xx가 발생합니다. validUser에서도 숫자 여부 검증이 없어 UnAuthorizedException으로 처리되지 않습니다. 토큰 스펙이 바뀌거나 잘못된 토큰이 왔을 때 장애로 이어지니, validUser 단계에서 숫자 여부까지 확인하고 실패 시 인증 예외를 던지도록 보강해 주세요. 동일한 파싱이 반복되는 다른 메서드에도 영향을 주니 함께 정리 부탁드립니다.

 private void validUser(UserContext user) {
-        if (user == null || user.getUserId() == null) {
-            throw new UnAuthorizedException(ErrorStatus.USER_UNAUTHORIZED.getMessage());
-        }
+        if (user == null || user.getUserId() == null) {
+            throw new UnAuthorizedException(ErrorStatus.USER_UNAUTHORIZED.getMessage());
+        }
+        try {
+            Long.parseLong(user.getUserId());
+        } catch (NumberFormatException e) {
+            throw new UnAuthorizedException(ErrorStatus.USER_UNAUTHORIZED.getMessage());
+        }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java
around lines 49 to 55, the code directly calls Long.parseLong(user.getUserId())
which will throw NumberFormatException for non-numeric userId; update validation
so validUser verifies user.getUserId() is a valid numeric string and throws the
existing UnAuthorizedException on failure, replace direct parseLong calls with a
single utility method (e.g., parseUserIdOrThrow) used everywhere to centralize
parsing and avoid repeated try/catch, and refactor other methods that parse
userId to use this validation/parsing helper so malformed tokens result in a
controlled authentication exception instead of a 5xx error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

게이트웨이에서 넘겨주는 userid는 String 형태잖아 그래서 Long.parseLong이렇게 바꾸는건데

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ksoheee 네, String에서 Long으로 변환하는 부분은 이해했습니다! 제가 우려했던 부분은 만약 게이트웨이에서 숫자가 아닌 userId가 넘어올 경우 NumberFormatException이 발생해서 5xx 에러가 나는 상황이었습니다.

게이트웨이가 항상 유효한 숫자 형태의 userId를 보장한다면 추가 검증은 필요 없을 것 같습니다. 혹시 게이트웨이에서 토큰 파싱 시 userId의 형식을 검증하고 있나요? 만약 그렇다면 현재 구현으로 충분합니다. 👍


🧠 Learnings used
Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 28
File: src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java:146-148
Timestamp: 2025-10-30T09:27:59.696Z
Learning: In the gearfirst-order-BE project, the `completeRepairAndGetParts` method in `PurchaseOrderServiceImpl` is called exclusively from the repair reception page, ensuring that the `receiptNum` parameter is always present and does not require null validation.

Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 26
File: src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java:93-98
Timestamp: 2025-10-28T05:05:49.715Z
Learning: In the Gear-First order backend (gearfirst-order-BE) Java Spring Boot project, when an endpoint performs state changes on the PurchaseOrder entity (such as calling order.completeRepair()), ensure the endpoint's Operation summary and description clearly document that state modification occurs, and use appropriate HTTP methods (POST/PATCH/PUT) rather than GET, even if the endpoint also returns data.

Copy link
Contributor Author

@ksoheee ksoheee Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니 게이트웨이에서는 userId를 항상 String으로 넘겨주지 jwt 토큰을 파싱해서 넘겨주는건데

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ksoheee 아, 이해했습니다! 게이트웨이에서 JWT 토큰을 검증하고 파싱해서 넘겨주는 거군요. 그렇다면 게이트웨이 단에서 이미 토큰의 유효성을 확인하고 있으니, 여기서 넘어오는 userId는 신뢰할 수 있는 값이겠네요.

게이트웨이가 JWT 검증을 담당하고 있다면 현재 구현으로 충분합니다. 제 우려를 명확하게 설명해주셔서 감사합니다! 👍


🧠 Learnings used
Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 28
File: src/main/java/com/gearfirst/backend/api/order/service/PurchaseOrderServiceImpl.java:146-148
Timestamp: 2025-10-30T09:27:59.696Z
Learning: In the gearfirst-order-BE project, the `completeRepairAndGetParts` method in `PurchaseOrderServiceImpl` is called exclusively from the repair reception page, ensuring that the `receiptNum` parameter is always present and does not require null validation.

Learnt from: ksoheee
Repo: Gear-First/gearfirst-order-BE PR: 26
File: src/main/java/com/gearfirst/backend/api/order/controller/PurchaseOrderController.java:93-98
Timestamp: 2025-10-28T05:05:49.715Z
Learning: In the Gear-First order backend (gearfirst-order-BE) Java Spring Boot project, when an endpoint performs state changes on the PurchaseOrder entity (such as calling order.completeRepair()), ensure the endpoint's Operation summary and description clearly document that state modification occurs, and use appropriate HTTP methods (POST/PATCH/PUT) rather than GET, even if the endpoint also returns data.

@ksoheee ksoheee merged commit 51b5fea into main Nov 9, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant